package com.csproj.basic.service;

import com.csproj.basic.BasicService;
import com.csproj.basic.domain.Container;
import com.csproj.basic.domain.Warehouse;
import com.csproj.basic.repository.ContainerRepository;
import com.csproj.basic.repository.WarehouseRepository;
import com.csproj.basic.service.dto.ContainerDTO;
import com.csproj.basic.service.mapper.ContainerMapper;
import com.csproj.dispatch.domain.Logistics;
import com.csproj.dispatch.domain.ProductInfo;
import com.csproj.dispatch.repository.LogisticsRepository;
import com.csproj.dispatch.repository.ProductInfoRepository;
import com.csproj.siiat.base.common.dto.BaseDTO;
import com.csproj.siiat.base.common.exception.BaseAppException;
import com.csproj.siiat.base.common.util.FileUtils;
import com.csproj.siiat.base.common.util.poi.POIUtil;
import com.csproj.siiat.security.SecurityUtils;
import com.csproj.system.service.UserInfoService;
import net.logstash.logback.encoder.org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Service Implementation for managing Container.
 */
@Service
@Transactional
public class ContainerService extends BasicService<ContainerDTO> {

    private final Logger log = LoggerFactory.getLogger(ContainerService.class);

    private final ContainerRepository containerRepository;

    private final ContainerMapper containerMapper;

    private final LogisticsRepository logisticsRepository;

    private final ProductInfoRepository productInfoRepository;

    private final WarehouseRepository warehouseRepository;

    private final UserInfoService userInfoService;

    public ContainerService(ContainerRepository containerRepository, ContainerMapper containerMapper,
                            LogisticsRepository logisticsRepository, ProductInfoRepository productInfoRepository,
                            UserInfoService userInfoService,
                            WarehouseRepository warehouseRepository) {
        this.containerRepository = containerRepository;
        this.containerMapper = containerMapper;
        this.logisticsRepository = logisticsRepository;
        this.productInfoRepository = productInfoRepository;
        this.userInfoService = userInfoService;
        this.warehouseRepository = warehouseRepository;
    }
    /**
     * 保存集装箱并且返回前端需要发的dto，包括扩展属性createName
     * @param containerDTO
     * @return containerDTO
     * TODO 主要负责从前端接收值
     * TODO DTO的扩展属性，在此方法复制
     */
    public ContainerDTO saveAndGetDTO(ContainerDTO containerDTO) {
        Container container = containerMapper.toEntity(containerDTO);
        container = save(container);
        containerDTO = containerMapper.toDto(container);
        return containerDTO;
    }

    /**
     * 保存集装箱
     * @param container
     * @return container
     * TODO 纯粹的保存方法，通用于所有保存业务调用
     * TODO 赋默认值，保存后，检查数据库，是否所有字段都有准确值
     */
    public Container save(Container container) {
        Container containerNo = containerRepository.findFirstByContainerNoAndDeletedFlagIsFalse(container.getContainerNo());
        if(StringUtils.isNotBlank(container.getId())){
            if(containerNo!=null && !containerNo.getId().equals(container.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }

        }
        else if(containerNo!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }
        //1是代表平台创建，2代表async
        container.setContainerSource("1");
        container.setCreationTime(ZonedDateTime.now());
        container.setCreatorUserId(SecurityUtils.getCurrentUserId());
        container.setDeletedFlag(false);
        return containerRepository.save(container);
    }

    /**
     * 修改集装箱并且返回前端需要发的dto，包括扩展属性
     * @param containerDTO
     * @return containerDTO
     * TODO 类似SAVE
     */
    public ContainerDTO updateAndGetDTO(ContainerDTO containerDTO) {
        Container container = containerRepository.findOne(containerDTO.getId());
        if(container == null){
            throw new BaseAppException(BaseDTO.CODE_PARAM,"id_errors");
        }
        container.setContainerNo(containerDTO.getContainerNo());
        container.setContainerSpecifications(containerDTO.getContainerSpecifications());
        container.setContainerColor(containerDTO.getContainerColor());
        container.setContainerCompanyId(containerDTO.getContainerCompanyId());
        container = update(container);
        return containerMapper.toDto(container);
    }

    /**
     * 修改集装箱
     * @param container
     * @return container
     * TODO 类似SAVE
     */
    public Container update(Container container) {
        Container containerNo = containerRepository.findFirstByContainerNoAndDeletedFlagIsFalse(container.getContainerNo());
        if(StringUtils.isNotBlank(container.getId())){
            if(containerNo!=null && !containerNo.getId().equals(container.getId())) {
                throw new BaseAppException(false,"duplicate_name");
            }
        }
        else if(containerNo!=null){
            throw  new BaseAppException(false,"duplicate_name");
        }
        Container containerDB = findOne(container.getId());
        containerDB.setContainerNo(container.getContainerNo());
        containerDB.setContainerSpecifications(container.getContainerSpecifications());
        containerDB.setContainerColor(container.getContainerColor());
        containerDB.setContainerCompanyId(container.getContainerCompanyId());

        containerDB = containerRepository.save(containerDB);
        return containerDB;
    }




    /**
     * TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     *
     * @return the list of entities
     */
    @Transactional(readOnly = true)
    public List<Container> findAll() {
        log.debug("Request to get all Containers");
        List<Container> containerList = containerRepository.findAll();
        return containerList;
    }

    /**
     *  获取所有集装箱信息
     *  @return
     *  TODO 返回DTO，包含扩展属性
     *  TODO 如果扩展属性不同，可写多个findAllAndGetDTO1、findAllAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public List<ContainerDTO> findAllAndGetDTO() {
        List<ContainerDTO> containerDTOS = containerMapper.toDto(findAll());
        return containerDTOS;
    }

    /**
     * 根据id，获取集装箱信息
     *  @param id the id of the entity
     *  @return the entity
     *
     *  TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public Container findOne(String id) {
        Container container = containerRepository.findOne(id);
        if(container == null){
            throw new BaseAppException(BaseDTO.CODE_PARAM,"id_errors");
        }
        return container;
    }


    /**
     *  获取所有集装箱信息（分页）
     *  @return the list of entities
     *
     *  TODO 返回纯粹的数据库对象，不包含扩展属性，适用于所有调取业务方法
     */
    @Transactional(readOnly = true)
    public Page<Container> findPageList(Map<String, Object> map, Pageable pageable) {
        Page<Container> result = containerRepository.findPageList(map,pageable);
        return result;
    }

    /**
     *  获取所有集装箱信息（分页）
     *  @return the list of entities
     *
     *  TODO 返回DTO，包含扩展属性
     *  TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public BaseDTO findPageListAndGetDTO(Map<String,Object> map, Pageable pageable) {
        if(StringUtils.isBlank((String) map.get("containerCompanyId"))){
            String siteId = userInfoService.getCurrentUserSiteId();
            map.put("siteId", siteId);
        }
        Page<Container> result = findPageList(map,pageable);
        List<Container> containers = result.getContent();
        List<ContainerDTO> containerDTOS = containerMapper.toDto(containers);
        extendCompanyName(containerDTOS);
        extendLogisticsAndProductInfo(containerDTOS);
        return BaseDTO.createBaseDTO(result).setFieldList(containerDTOS);
    }


    private void extendLogisticsAndProductInfo(List<ContainerDTO> containerDTOS){

        List<String> containerIds = containerDTOS.stream().map(c->c.getId()).collect(Collectors.toList());
        if(containerIds.size()>0){
            List<Logistics> logistics = logisticsRepository.findByContainerIds(containerIds);
            List<ProductInfo> productInfos = productInfoRepository.findByContainerIds(containerIds);
            for (ContainerDTO containerDTO : containerDTOS) {
                Logistics l = logistics.stream().filter(ls->ls.getContainerId().equals(containerDTO.getId())).findFirst().orElse(null);
                ProductInfo productInfo = productInfos.stream().filter(p->containerDTO.getId().equals(p.getContainerId())).findFirst().orElse(null);
                containerDTO.setHasLogistics(l!=null?"1":"2");
                containerDTO.setHasProductInfo(productInfo!=null?"1":"2");
            }
        }

    }
    /**
     * 根据id，获取集装箱信息
     *  @param id 主键id
     *  @return creator、questionTypeName
     *
     *  TODO 返回DTO，包含扩展属性
     *  TODO 如果扩展属性不同，findPageListAndGetDTO1、findPageListAndGetDTO2，注明扩展的属性
     */
    @Transactional(readOnly = true)
    public ContainerDTO findOneAndGetDTO(String id) {
        Container container = findOne(id);
        ContainerDTO containerDTO = containerMapper.toDto(container);
        extendSiteName(containerDTO);
        extendManagerName(containerDTO);
        return containerDTO;
    }

    /**
     *  根据id，删除集装箱信息
     *  @param id the id of the entity
     */
    public void delete(String id) {
        containerRepository.delete(id);
    }

    /**
     * 根据机构ids，批量删除集装箱信息
     * @param ids
     */
    public void deleteIds(String[] ids){
        containerRepository.deleteIds(ids);
    }

    /**
     * 上传文件
     * @param file
     */
    public String uploadFile(HttpServletRequest request, MultipartFile file){
        String filePath = FileUtils.excelUpload(request,file, File.separator+"upload"+ File.separator+"warehouse");
        return filePath;
    }

    /**
     * 上传文件
     * @param file
     */
    public BaseDTO  batchImport(MultipartFile file){
        try {
            List<String[]> readResult = POIUtil.readExcel(file);

            if(readResult.size()==0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("upload_faild");
            }
            List<Container> containers = new ArrayList<>();
            List<Warehouse> sites = warehouseRepository.findAll();
            StringBuilder errmsg = new StringBuilder();
            int i = 2;
            for (String[] u : readResult) {
                try {
                    Container uname = containerRepository.findFirstByContainerNoAndDeletedFlagIsFalse(u[0]);
                    if(uname!=null){
                        errmsg.append(i-1).append(",");
                    }else{
                        Container container = new Container();
                        i++;
                        container.setDeletedFlag(false);
                        container.setEnableFlag(true);
                        container.setContainerNo(u[0]);
                        container.setContainerSpecifications(u[1]);
                        container.setContainerColor(u[2]);
                        if(StringUtils.isNotBlank(u[3]))
                        {
                            Warehouse warehouse = sites.stream().filter(s->s.getHouseName().equals(StringUtils.trim(u[3]))).findFirst().orElse(new Warehouse());
                            container.setContainerCompanyId(warehouse.getId());
                        }
                        containers.add(container);
                    }

                }catch (Exception e){
                    errmsg.append(i-1).append(",");
                }
            }

            if(containers.size()>0)
                containerRepository.save(containers);
            String msg = "";
            if(errmsg.length()>0)
            {
                return  BaseDTO.createBaseDTO().setSuccess(false).setMessage("partial_upload_faild");
            }
        } catch (IOException e) {
            throw new BaseAppException(false,"upload_error");
        }
        return BaseDTO.createBaseDTO().setSuccess(true);
    }

}
